package project5;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

/**
 * This class contains the main method. This takes as input a file path and optionally a string
 * of custom delimiters, otherwise it uses the following characters denoted between the <<< >>> symbols
 * but not including the <<< and >>>: <<< :/.,+*()~&%$#!`\"{}|^[]\\@?<>=;>>>. Also,characters with
 * octal values less than 40 or greater than or equal to 177 are considered fixed 
 * delimiters and cannot be overridden by the user. It will then print out the number of words in the document. 
 * To use the default delimiters, use the following in commmand line argument format:
 * <<< java Project1 file_path >>>
 * 
 * To use the custom delimiters, use the -b flag and provide a string of delimiters 
 * enclosed in quotations followed by the file path. 
 *
 * <<< java Project1 -b "#$(%)$! ^%@!" file_path >>>  
 * 
 * @author Surabhi Diwan
 */
public class WordCounter
{
	/** The number of words counted by this WordCounter. */
	private int word_count = 0;
	public static long _bytesRead;
	
	private String _breakCharacters = " :/.,+*()~&%$#!`\"{}|^[]\\@?<>=;";
	
	/**
	 * main method
	 * @param args the command line arguments
	 */
	public ArrayList<String> WordCreator(String filePath) throws ProjectException
	{
		ArrayList<String> toReturn = new ArrayList<String>();
		
		BufferedReader reader = null;
		StringBuilder word = new StringBuilder();
		char current;
		String line = null;
		String temp;
		boolean inWord = false;
		
		try
		{
			//Read lines
			reader = new BufferedReader(new FileReader(filePath));
			
			while ((line = reader.readLine()) != null)
			{
				//Read words
				for (int i = 0; i < line.length(); i++)
				{
					current = line.charAt(i);
					
					if (inWord)
					{
						if (isBreakCharacter(current))
						{
							inWord = false;
							toReturn.add(word.toString());
							word = new StringBuilder();
						}
						else
						{
							word.append(current);
						}
					}
					else
					{
						if (!isBreakCharacter(current))
						{
							inWord = true;
							word.append(current);
						}
					}
				}
				
				if (inWord)
				{
					temp = word.toString();
					
					if (!(temp.length() == 0))
					{
						toReturn.add(word.toString());
					}
					
					word = new StringBuilder();
				}
			}
			
			_bytesRead = new File(filePath).length();
			
		}
		catch (FileNotFoundException fnfe)
		{
			throw new ProjectException(ErrorUtility.CANNOT_FIND_FILE);
		}
		catch (IOException ioe)
		{
			throw new ProjectException(ErrorUtility.CANNOT_READ_FILE);
		}
		catch (Exception e)
		{
			throw new ProjectException(ErrorUtility.UNCAUGHT_EXCEPTION);
		}
		finally
		{
			if (null != reader)
			{
				try
				{
					reader.close();
				}
				catch (IOException ioe)
				{
					//Ignore
				}
			}
		}
				
		return toReturn;
	}
	
	public int getWordCount()
	{
		return word_count;
	}
	
	public void addBreakCharacters(String characters)
	{
		if (null != characters)
		{
			_breakCharacters += characters;
		}
	}
	
	public String getBreakCharacters()
	{
		return _breakCharacters;
	}
	
	/**
	 * Checks to see if the given character is a break character.  The two
	 *  classes of break character are variable and fixed.  Variable break
	 *  characters are stored in _breakCharacters and may be overridden by the
	 *  user.  Fixed break characters are not overridable and are those with
	 *  int values in the ranges [0, 40] and [177, 255]. 
	 * 
	 * @param c The character to check.
	 * @return Whether the character is a break character.
	 */
	private boolean isBreakCharacter(char c)
	{
		if (_breakCharacters.contains("" + c))
		{
			return true;
		}
		
		if ((c < 40) || (c > 177))
		{
			return true;
		}
		
		return false;
	}
}
